package cc.eddic.examinationsystem.config;

import cc.eddic.examinationsystem.Role;
import cc.eddic.examinationsystem.repository.StudentRepository;
import cc.eddic.examinationsystem.service.UserDetailsServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Slf4j
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final LoggingAccessDeniedHandler accessDeniedHandler;

    private final StudentRepository userRepository;

    private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    @Autowired
    public SecurityConfig(LoggingAccessDeniedHandler accessDeniedHandler, StudentRepository userRepository, CustomAuthenticationFailureHandler customAuthenticationFailureHandler, CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
        this.accessDeniedHandler = accessDeniedHandler;
        this.userRepository = userRepository;
        this.customAuthenticationFailureHandler = customAuthenticationFailureHandler;
        this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers(
                        "/",
                        "/401",
                        "/403",
                        "/login",
                        "/logout",
                        "/student/add",
                        "/student/save",
                        "/favicon.ico",
                        "/assets/**",
                        "/js/**",
                        "/css/**",
                        "/img/**").permitAll()
                .antMatchers("/answerbook/**").hasAuthority(Role.EXAMINEE.toString())
                .antMatchers("/studentExam/**").hasAnyAuthority(Role.EXAMINEE.toString(), Role.PROJECT_MANAGER.toString())
                .antMatchers("/exam/**").hasAuthority(Role.PROJECT_MANAGER.toString())
                .antMatchers("/exam_student/**").hasAuthority(Role.PROJECT_MANAGER.toString())
                .antMatchers("/student/**").hasAuthority(Role.PROJECT_MANAGER.toString())
                .antMatchers("/questions/**").hasAuthority(Role.QUESTION_BANK_ADMIN.toString())
                .antMatchers("/question/**").hasAuthority(Role.EXAMINER.toString())
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .loginPage("/login")
                    .failureHandler(customAuthenticationFailureHandler)
                    .defaultSuccessUrl("/landing")
                    .permitAll()
                .and()
                .logout()
                    .invalidateHttpSession(true)
                    .clearAuthentication(true)
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/login?logout")
                    .permitAll()
                .and()
                .exceptionHandling()
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    .accessDeniedHandler(accessDeniedHandler)
        ;
    }

    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl(userRepository);
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService());
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }
}
